#include "libGeoutils/tool/datetime_tool.h"
#include <iostream>
#include <string> 
#include <chrono> 
#include <ctime>  
#include <iomanip>
#include <sstream>

#define YEAR_BASE 1900
#define YEAR_KEY "year"
#define MONTH_KEY "month"
#define DAY_KEY "day"
#define HOUR_KEY "hour"
#define MINUTE_KEY "minute"
#define SECONDS_KEY "seconds"

static std::string getCurrentDateTime()
{
	auto now = std::chrono::system_clock::now();
	std::time_t currentTime_t = std::chrono::system_clock::to_time_t(now);
	std::tm* localTime = std::localtime(&currentTime_t);

	if (localTime == nullptr) {
		return " Error ( Failed to convert time to local time structure ) ";
	}

	std::stringstream ss;
	ss << std::put_time(localTime, "%Y-%m-%d %H:%M:%S");
	return ss.str();
}

static std::string getCurrentDateTimeWithMs() 
{
	auto now = std::chrono::system_clock::now();
	auto timeSinceEpoch = now.time_since_epoch();

	auto seconds = std::chrono::duration_cast<std::chrono::seconds>(timeSinceEpoch);
	auto milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(timeSinceEpoch - seconds);

	std::time_t currentTime_t = std::chrono::system_clock::to_time_t(now);
	std::tm* localTime = std::localtime(&currentTime_t);

	if (localTime == nullptr) {
		return " Error ( Failed to convert time to local time structure ) ";
	}

	std::stringstream ss;
	ss << std::put_time(localTime, "%Y-%m-%d %H:%M:%S") << "." << std::setfill('0') << std::setw(3) << milliseconds.count();
	return ss.str();
}

geo::tool::DateTime::csptr geo::tool::DateTime::now()
{
	geo::tool::DateTime::csptr cspDateTime;

	auto now = std::chrono::system_clock::now();
	std::time_t currentTime_t = std::chrono::system_clock::to_time_t(now);
	std::tm* localTime = std::localtime(&currentTime_t);

	if (localTime == nullptr) {
		return cspDateTime;
	}

	cspDateTime = std::make_shared<geo::tool::DateTime>(
		localTime->tm_year + YEAR_BASE,
		localTime->tm_mon + 1,
		localTime->tm_mday,
		localTime->tm_hour,
		localTime->tm_min,
		localTime->tm_sec
	);

	return cspDateTime;
}

std::string geo::tool::DateTime::now_str()
{
	return getCurrentDateTimeWithMs();
}

geo::tool::DateTime::DateTime(int year, int month, int day, int hour, int minute, int seconds)
{
	setProperty(YEAR_KEY, year);
	setProperty(MONTH_KEY, month);
	setProperty(DAY_KEY, day);
	setProperty(HOUR_KEY, hour);
	setProperty(MINUTE_KEY, minute);
	setProperty(SECONDS_KEY, seconds);
}

geo::tool::DateTime::~DateTime()
{
}

void geo::tool::DateTime::setYear(int year)
{
	setProperty(YEAR_KEY, year);
}

int geo::tool::DateTime::getYear() const
{
	int year = 0;
	getProperty(YEAR_KEY, year);
	return year;
}

void geo::tool::DateTime::setMonth(int month)
{
	setProperty(MONTH_KEY, month);
}

int geo::tool::DateTime::getMonth() const
{
	int month = 0;
	getProperty(MONTH_KEY, month);
	return month;
}

void geo::tool::DateTime::setDay(int day)
{
	setProperty(DAY_KEY, day);
}

int geo::tool::DateTime::getDay() const
{
	int day = 0;
	getProperty(DAY_KEY, day);
	return day;
}

void geo::tool::DateTime::setHour(int hour)
{
	setProperty(HOUR_KEY, hour);
}

int geo::tool::DateTime::getHour() const
{
	int hour = 0;
	getProperty(HOUR_KEY, hour);
	return hour;
}

void geo::tool::DateTime::setMinute(int minute)
{
	setProperty(MINUTE_KEY, minute);
}

int geo::tool::DateTime::getMinute() const
{
	int minute = 0;
	getProperty(MINUTE_KEY, minute);
	return minute;
}

void geo::tool::DateTime::setSeconds(int seconds)
{
	setProperty(SECONDS_KEY, seconds);
}

int geo::tool::DateTime::getSeconds() const
{
	int seconds = 0;
	getProperty(SECONDS_KEY, seconds);
	return seconds;
}

std::string geo::tool::DateTime::toString() const
{
	std::stringstream ss;
	ss << getYear() 
		<< std::setfill('0') << std::setw(2) << getMonth() 
		<< std::setfill('0') << std::setw(2) << getDay() 
		<< "_"
		<< std::setfill('0') << std::setw(2) << getHour() 
		<< std::setfill('0') << std::setw(2) << getMinute() 
		<< "_"
		<< std::setfill('0') << std::setw(2) << getSeconds();
	return ss.str();
}
